﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Collections;
using System.Threading.Tasks;
using System.IO;

namespace JeanFish.AnA.OAuth2
{
    public abstract class Client
    {
        public Client(string clientId, string clientSecret, string tokenEndpoint)
        {
            if (!Syntaxes.ClientIDSyntax.IsMatch(clientId))
                throw new MalformedSyntaxException(Syntaxes.ClintIDSyntaxName, Resources.Exception_ClientIDMalformed);
            if (!Syntaxes.ClientSecretSyntax.IsMatch(clientSecret))
                throw new MalformedSyntaxException(Syntaxes.ClientSecretSyntaxName, Resources.Exception_ClientSecretMalformed);
            this.ClientId = clientId;
            this.ClientSecret = ClientSecret;
            this.TokenEndpoint = new TokenEndpoint(tokenEndpoint);
        }
        public abstract ClientType Type { get; }
        public abstract string Profile { get; }
        public string ClientId { get; protected set; }
        public string ClientSecret { get; protected set; }
        public abstract GrantType GrantType { get; }
        public TokenEndpoint TokenEndpoint { get; protected set; }
    }

    public enum ClientType
    {
        Confidential,
        Public
    }
    public class WebServerClient : Client
    {
        public WebServerClient(string clientId, string clientSecret, string tokenEndpoint, string authorizationEndpoint)
            : base(clientId, clientSecret, tokenEndpoint)
        {
            this.AuthorizationEndpoint = new AuthorizationEndpoint(authorizationEndpoint);
        }

        public sealed override ClientType Type
        {
            get { return ClientType.Confidential; }
        }

        public sealed override string Profile
        {
            get { return "web application"; }
        }

        public sealed override GrantType GrantType
        {
            get { return GrantType.AuthorizationCode; }
        }

        public AuthorizationEndpoint AuthorizationEndpoint { get; protected set; }

        public Task<string> ObtainAuthorizationAsync(RequestParameterCollection parameters)
        {
            HttpWebRequest request = WebRequest.Create(this.AuthorizationEndpoint.URI.OriginalString + parameters.GetQueryString()) as HttpWebRequest;
            var task = Task.Factory.FromAsync(
                request.BeginGetResponse,
                asyncResult => request.EndGetResponse(asyncResult),
                null);
            return task.ContinueWith(t => ReadStreamFromResponse(t.Result));
        }
        private static string ReadStreamFromResponse(WebResponse response)
        {
            using (var responseStream = response.GetResponseStream())
            {
                var reader = new StreamReader(responseStream);
                var content = reader.ReadToEnd();
                return content;
            }
        }

    }
    public class RequestParameterCollection : IEnumerable
    {
        Dictionary<string, string> parameters = new Dictionary<string, string>();
        public string this[string parameterName]
        {
            get { return this.parameters[parameterName]; }
            set { this.parameters[parameterName] = value; }
        }
        public string GetQueryString()
        {
            StringBuilder builder = new StringBuilder();
            foreach (var param in parameters)
            {
                builder.AppendFormat("&{0}={1}", param.Key, param.Value);
            }
            if (parameters.Count > 1)
            {
                builder.Remove(0, 1);
                builder.Insert(0, "?");
            }
            return builder.ToString();

        }
        public IEnumerator GetEnumerator()
        {
            return parameters.GetEnumerator();
        }
    }
}
